home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / shop.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  18KB  |  606 lines

  1. /*
  2.  * static char *rcsid_shop_c =
  3.  *   "$Id: shop.c,v 1.32 1996/01/02 11:49:55 master Exp $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27.  
  28. */
  29.  
  30. #include <global.h>
  31. #include <spells.h>
  32. #include <skills.h>
  33. #include <living.h>
  34. #include <newclient.h>
  35. #ifndef __CEXTRACT__
  36. #include <sproto.h>
  37. #endif
  38.  
  39.  
  40. #define NUM_COINS 3    /* number of coin types */
  41. static char *coins[] = {"platinacoin", "goldcoin", "silvercoin", NULL};
  42.  
  43.  
  44. /* Added F_TRUE flag to define.h to mean that the price should not
  45.  * be adjusted by players charisma. With F_TRUE, it returns the amount
  46.  * that the item is worth, if it was sold, but unadjusted by charisma.
  47.  * This is needed for alchemy, to to determine what value of gold nuggets
  48.  * should be given (the gold nuggets, when sold, will have the adjustment
  49.  * by charisma done at that time).  NULL could have been passed as the
  50.  * who parameter, but then the adjustment for expensive items (>10000)
  51.  * would not be done.
  52.  * 
  53.  * CF 0.91.4 - This function got changed around a bit.  Now the
  54.  * number of object is multiplied by the value early on.  This fixes problems
  55.  * with items worth very little.  What happened before is that various
  56.  * divisions took place, the value got rounded to 0 (Being an int), and
  57.  * thus remained 0.
  58.  *
  59.  * Mark Wedel (master@rahul.net)
  60.  */
  61. int query_cost(object *tmp, object *who, int flag) {
  62.   int val;
  63.   int number;    /* used to better calculate value */
  64.   int charisma;
  65.  
  66.   if (tmp->type==MONEY) return (tmp->nrof * tmp->value);
  67.   if (tmp->type==GEM) {
  68.     if (flag==F_TRUE) return (tmp->nrof * tmp->value);
  69.     if (flag==F_BUY) return (1.03 * tmp->nrof * tmp->value);
  70.     if (flag==F_SELL) return (0.97 * tmp->nrof * tmp->value);
  71.     LOG(llevError,"Query_cost: Gem type with unknown flag : %d\n", flag);
  72.     return 0;
  73.   }
  74.   number = tmp->nrof;
  75.   if (number==0) number=1;
  76.   if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) || !need_identify(tmp)) {
  77.     if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))
  78.       return 0;
  79.     else
  80.       val=tmp->value * number;
  81.   }
  82.   /* This area deals with objects that are not identified, but can be */
  83.   else {
  84.     if (tmp->arch != NULL) {
  85.       if (flag == F_BUY) {
  86.         LOG(llevError, "Asking for buy-value of unidentified object.");
  87.         val = tmp->arch->clone.value * 50 * number;
  88.       }
  89.       else    /* Trying to sell something, or get true value */
  90.         if (tmp->type == POTION)
  91.           val = number * 1000; /* Don't want to give anything away */
  92.         else
  93.           val = number * tmp->arch->clone.value / 3;
  94.     } else { /* No archetype with this object */
  95.       LOG(llevDebug,"In sell item: Have object with no archetype: %s\n", tmp->name);
  96.       if (flag == F_BUY) {
  97.         LOG(llevError, "Asking for buy-value of unidentified object without arch.");
  98.         val = number * tmp->value * 10;
  99.       }
  100.       else
  101.         val = number * tmp->value / 5;
  102.     }
  103.   }
  104.   if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && QUERY_FLAG(tmp, FLAG_BEEN_APPLIED))
  105.     val = val * 2 / 3;
  106.  
  107.   /* If the item has been applied or identifed or does not need to be
  108.    * identified, AND the object is magical and the archetype is non
  109.    * magical, then change values accordingly.  The tmp->arch==NULL is
  110.    * really just a check to prevent core dumps for when it checks
  111.    * tmp->arch->clone.magic for any magic.  The check for archetype
  112.    * magic is to not give extra money for archetypes that are by
  113.    * default magical.  This is because the archetype value should have
  114.    * already figured in that value.
  115.    */
  116.   if((QUERY_FLAG(tmp, FLAG_IDENTIFIED)||!need_identify(tmp)||
  117.      QUERY_FLAG(tmp, FLAG_BEEN_APPLIED)) &&
  118.      tmp->magic&&(tmp->arch==NULL||!tmp->arch->clone.magic)) {
  119.     if(tmp->magic>0)
  120.               val*=(3*tmp->magic*tmp->magic*tmp->magic);
  121.         else
  122.       /* Note that tmp->magic is negative, so that this
  123.        * will actually be something like val /=2, /=3, etc.
  124.        */
  125.           val/=(1-tmp->magic);
  126.      }
  127.   if (flag==F_BUY)
  128.     val*=6; /* For charisma 25, the price is now x1.5 */
  129.  
  130.   if (tmp->type==WAND) {
  131.     if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) || !need_identify(tmp))
  132.       val=(val*tmp->stats.food)/spells[tmp->stats.sp].charges;
  133.     else
  134.       val/=3;
  135.   }
  136.  
  137.   if (flag==F_TRUE || flag==F_SELL) {
  138.     if (val/number>10000) {
  139.     val=8000+isqrt((int)val/number)*20;
  140.     val *= number;
  141.     }
  142.   }
  143.  
  144. /* this  modification is for merchant skill 
  145.  * now players with readied merchant skill get 
  146.  * more Cha up to the limit of modified Cha = 30.
  147.  * -b.t. thomas@nomad.astro.psu.edu 
  148.  */
  149.  
  150.   if (who!=NULL && who->type==PLAYER) { 
  151.       charisma = who->stats.Cha;  /* used for SK_BARGAINING modification */ 
  152.       if(who->contr->shoottype == range_skill && who->chosen_skill)
  153.          if(who->chosen_skill->stats.sp == SK_BARGAINING) { 
  154.         charisma = who->stats.Cha + (who->level+2)/3;
  155.         if(charisma>30) charisma = 30;
  156.          }
  157.       if(flag==F_BUY)
  158.           val=(val*(100-cha_bonus[charisma]))/100;
  159.       else if (flag==F_SELL)
  160.           val=(val*100)/(100-cha_bonus[charisma]);
  161.   }
  162.   if(val<0)
  163.     val=1000000;
  164.   return (int)val;
  165. }
  166.  
  167. /* Find the coin type that is worth more the 'c'.  Starts at the
  168.  * cointype placement.
  169.  */
  170.  
  171. static archetype *find_next_coin(int c, int *cointype) {
  172.   archetype *coin;
  173.  
  174.   do {
  175.     if (coins[*cointype]==NULL) return NULL;
  176.     coin = find_archetype(coins[*cointype]);
  177.     if (coin == NULL)
  178.       return NULL;
  179.     *cointype += 1;
  180.   } while (coin->clone.value > c);
  181.  
  182.   return coin;
  183. }
  184.  
  185. /* This returns a string of how much somethign is worth based on
  186.  * an integer being passed.
  187.  */
  188. char *cost_string_from_value(int cost)
  189. {
  190.   static char buf[MAX_BUF];
  191.   archetype *coin, *next_coin;
  192.   char *endbuf;
  193.   int num, cointype = 0;
  194.  
  195.   coin = find_next_coin(cost, &cointype);
  196.   if (coin == NULL)
  197.     return "nothing";
  198.  
  199.   num = cost / coin->clone.value;
  200.   cost -= num * coin->clone.value;
  201.   if (num == 1)
  202.     sprintf(buf, "1 %s", coin->clone.name);
  203.   else
  204.     sprintf(buf, "%d %ss", num, coin->clone.name);
  205.  
  206.   next_coin = find_next_coin(cost, &cointype);
  207.   if (next_coin == NULL)
  208.     return buf;
  209.  
  210.   do {
  211.     endbuf = buf + strlen(buf);
  212.  
  213.     coin = next_coin;
  214.     num = cost / coin->clone.value;
  215.     cost -= num * coin->clone.value;
  216.  
  217.     if (cost == 0)
  218.       next_coin = NULL;
  219.     else
  220.       next_coin = find_next_coin(cost, &cointype);
  221.  
  222.     if (next_coin) {
  223.       /* There will be at least one more string to add to the list,
  224.        * use a comma.
  225.        */
  226.       strcat(endbuf, ", "); endbuf += 2;
  227.     } else {
  228.       strcat(endbuf, " and "); endbuf += 5;
  229.     }
  230.     if (num == 1)
  231.       sprintf(endbuf, "1 %s", coin->clone.name);
  232.     else
  233.       sprintf(endbuf, "%d %ss", num, coin->clone.name);
  234.   } while (next_coin);
  235.  
  236.   return buf;
  237. }
  238.  
  239. char *query_cost_string(object *tmp,object *who,int flag) {
  240.   return cost_string_from_value(query_cost(tmp,who,flag));
  241. }
  242.  
  243. /* This function finds out how much money the player is carrying,
  244.  * and returns that value
  245.  */
  246.  
  247. int query_money(object *op) {
  248.     object *tmp;
  249.     int    total=0;
  250.  
  251.     if (op->type!=PLAYER) {
  252.     LOG(llevError, "Query money called with non player");
  253.     return 0;
  254.     }
  255.     for (tmp = op->inv; tmp; tmp= tmp->below) {
  256.     if (tmp->type==MONEY)
  257.         total += tmp->nrof * tmp->value;
  258.     }
  259.     return total;
  260. }
  261.  
  262. /* This pays for the item, and takes the proper amount of money off
  263.  * the player. 
  264.  * CF 0.91.4 - this function is mostly redone in order to fix a bug
  265.  * with weight not be subtracted properly.  We now remove and
  266.  * insert the coin objects -  this should update the weight
  267.  * appropriately
  268.  */
  269.  
  270. int pay_for_item(object *op,object *pl) {
  271.     int item_cost=query_cost(op,pl,F_BUY),i, count;
  272.     int to_pay;
  273.     object *tmp, *coin_objs[NUM_COINS];
  274.     archetype *at;
  275.  
  276.     if (item_cost==0) return 1;
  277.     if(item_cost>query_money(pl))
  278.         return 0;
  279.  
  280.  
  281.     for (i=0; i<NUM_COINS; i++) {
  282.     coin_objs[i] = NULL;
  283.     }
  284.     pl->contr->freeze_inv=1;
  285.  
  286.     /* This hunk should remove all the money objects from the player */
  287.     while ((tmp=present_in_ob(MONEY, pl))!=NULL) {
  288.         for (i=0; i<NUM_COINS; i++) {
  289.         if (!strcmp(coins[NUM_COINS-1-i], tmp->arch->name)) {
  290.  
  291.         /* This should not happen, but if it does, just
  292.          * merge the two.
  293.          */
  294.         if (coin_objs[i]!=NULL) {
  295.             LOG(llevError,"%s has two money entries of (%s)\n",
  296.             pl->name, coins[NUM_COINS-1-i]);
  297.             remove_ob(tmp);
  298.             coin_objs[i]->nrof += tmp->nrof;
  299.             if (pl->contr->eric_server)
  300.             esrv_del_item(pl->contr->eric_server, tmp->count);
  301.             free_object(tmp);
  302.         }
  303.         else {
  304.             remove_ob(tmp);
  305.             if (pl->contr->eric_server)
  306.             esrv_del_item(pl->contr->eric_server, tmp->count);
  307.             coin_objs[i] = tmp;
  308.         }
  309.         break;
  310.         }
  311.     }
  312.     if (i==NUM_COINS)
  313.         LOG(llevError,"in pay_for_item: Did not find string match for %s\n", tmp->arch->name);
  314.     }
  315.  
  316.     /* Fill in any gaps in the coin_objs array - needed to make change. */
  317.     /* Note that the coin_objs array goes from least value to greatest value */
  318.     for (i=0; i<NUM_COINS; i++)
  319.     if (coin_objs[i]==NULL) {
  320.         at = find_archetype(coins[NUM_COINS-1-i]);
  321.         if (at==NULL) LOG(llevError, "Could not find %s archetype", coins[NUM_COINS-1-i]);
  322.         coin_objs[i] =get_object();
  323.         copy_object(&at->clone, coin_objs[i]);
  324.         coin_objs[i]->nrof = 0;
  325.     }
  326.  
  327.     to_pay = item_cost;
  328.     for (i=0; i<NUM_COINS; i++) {
  329.     int num_coins;
  330.  
  331.     if (coin_objs[i]->nrof*coin_objs[i]->value> to_pay) {
  332.         num_coins = to_pay / coin_objs[i]->value;
  333.         if (num_coins*coin_objs[i]->value< to_pay) num_coins++;
  334.     }
  335.     else 
  336.         num_coins = coin_objs[i]->nrof;
  337.  
  338.     to_pay -= num_coins * coin_objs[i]->value;
  339.     coin_objs[i]->nrof -= num_coins;
  340.     /* Now start making change.  Start at the coin value
  341.      * below the one we just did, and work down to
  342.      * the lowest value.
  343.      */
  344.     count=i-1;
  345.     while (to_pay<0 && count>=0) {
  346.         num_coins = -to_pay/ coin_objs[count]->value;
  347.         coin_objs[count]->nrof += num_coins;
  348.         to_pay += num_coins * coin_objs[count]->value;
  349.         count--;
  350.     }
  351.     }
  352.     for (i=0; i<NUM_COINS; i++) {
  353.     if (coin_objs[i]->nrof) {
  354.         object *tmp = insert_ob_in_ob(coin_objs[i], pl);
  355.         if (pl->contr->eric_server > 0)
  356.         esrv_send_item(pl, tmp);
  357.     } else
  358.         free_object(coin_objs[i]);
  359.     }
  360.     if(QUERY_FLAG(pl,FLAG_WAS_WIZ))
  361.       SET_FLAG(op, FLAG_WAS_WIZ);
  362.     pl->contr->freeze_inv=0;
  363.     fix_player(pl);
  364.     return 1;
  365. }
  366.  
  367. /* Eneq(@csd.uu.se): Better get_payment, descends containers looking for
  368.    unpaid items. get_payment is now used as a link. To make it simple
  369.    we need the player-object here. */
  370.  
  371. int get_payment2 (object *pl, object *op) {
  372.     char buf[MAX_BUF];
  373.     int ret=1;
  374.  
  375.     if (op!=NULL&&op->inv)
  376.         ret = get_payment2(pl, op->inv);
  377.  
  378.     if (!ret) 
  379.         return 0;
  380.  
  381.     if (op!=NULL&&op->below) 
  382.         ret = get_payment2 (pl, op->below);
  383.  
  384.     if (!ret) 
  385.         return 0;
  386.    
  387.     if(op!=NULL&&QUERY_FLAG(op,FLAG_UNPAID)) {
  388.         strncpy(buf,query_cost_string(op,pl,F_BUY),MAX_BUF);
  389.         if(!pay_for_item(op,pl)) {
  390.             int i=query_cost(op,pl,F_BUY) - query_money(pl);
  391.         CLEAR_FLAG(op, FLAG_UNPAID);
  392.         new_draw_info_format(NDI_UNIQUE, 0, pl,
  393.         "You lack %s to buy %s.", cost_string_from_value(i),
  394.         query_name(op));
  395.         SET_FLAG(op, FLAG_UNPAID);
  396.             return 0;
  397.         } else {
  398.         object *tmp;
  399.         long c = op->count;
  400.  
  401.         CLEAR_FLAG(op, FLAG_UNPAID);
  402.         new_draw_info_format(NDI_UNIQUE, 0, op,
  403.         "You paid %s for %s.",buf,query_name(op));
  404.         tmp=merge_ob(op,NULL);
  405.         if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  406.         if (tmp) {      /* it was merged */
  407.             esrv_del_item (pl->contr->eric_server, c);
  408.             op = tmp;
  409.         }
  410.             esrv_send_item(pl, op);
  411.         }
  412.     }
  413.     }
  414.     return 1;
  415. }
  416.  
  417. int get_payment(object *pl) {
  418.   int ret;
  419.  
  420.   D_LOCK(pl);
  421.  
  422.   ret = get_payment2 (pl, pl->inv);
  423.  
  424.   D_UNLOCK(pl);
  425.   if (pl->type == PLAYER && pl->contr->eric_server <= 0)
  426.     draw_inventory(pl);
  427.   return ret;
  428. }
  429.  
  430. /* Modified function to give out platinum coins.  This function is
  431.  * not as general as pay_for_item in finding money types - each
  432.  * new money type needs to be explicity code in here.
  433.  */
  434.  
  435. void sell_item(object *op, object *pl) {
  436.   int i=query_cost(op,pl,F_SELL), count;
  437.   object *tmp;
  438.   archetype *at;
  439.  
  440.   if(pl==NULL||pl->type!=PLAYER) {
  441.     LOG(llevDebug,"Object other than player tried to sell something.\n");
  442.     return;
  443.   }
  444.   if(!i) {
  445.     new_draw_info_format(NDI_UNIQUE, 0, pl,
  446.     "We're not interested in %s.",query_name(op));
  447.  
  448.     /* Even if the character doesn't get anything for it, it may still be
  449.      * worth something.  If so, make it unpaid
  450.      */
  451.     if (op->value)
  452.       SET_FLAG(op, FLAG_UNPAID);
  453.     identify(op);
  454.     return;
  455.   }
  456.   D_LOCK(pl);
  457.   for (count=0; coins[count]!=NULL; count++) {
  458.     at = find_archetype(coins[count]);
  459.     if (at==NULL) LOG(llevError, "Could not find %s archetype", coins[count]);
  460.     else if ((i/at->clone.value)) {
  461.     tmp = get_object();
  462.     copy_object(&at->clone, tmp);
  463.     tmp->nrof = i/tmp->value;
  464.     i -= tmp->nrof * tmp->value;
  465.     tmp = insert_ob_in_ob(tmp, pl);
  466.     if(pl->contr->eric_server > 0)
  467.         esrv_send_item (pl, tmp);
  468.     }
  469.   }
  470.  
  471.   if (i!=0) 
  472.     LOG(llevError,"Warning - payment not zero: %d\n", i);
  473.  
  474.   D_UNLOCK(pl);
  475.   new_draw_info_format(NDI_UNIQUE, 0, pl,
  476.     "You receive %s for %s.",query_cost_string(op,pl,1),
  477.           query_name(op));
  478.   SET_FLAG(op, FLAG_UNPAID);
  479.   identify(op);
  480. }
  481.  
  482.  
  483. /* SHOP_LISTINGS code added by Mark Wedel (master@cats.ucsc.edu)
  484.  *
  485.  * I put the code here, because it did seem shop related.  I suppose it
  486.  * could also be put in the apply.c file.
  487.  *
  488.  * Various thoughts:
  489.  *
  490.  * Perhaps the location of the item relative to the menu sign should be given?
  491.  *
  492.  * Perhaps a better ordering/sorting of the objects could be done? (group
  493.  * all chain armor together, and then order by magic plus value, for
  494.  * example.)
  495.  *
  496.  * Tell the price of the item also?
  497.  */
  498.  
  499. void shop_listing_more(object *op)
  500. {
  501.     object *tmp,*old;
  502.     int lines = 7;
  503.  
  504.     tmp = op->contr->menu->inv;
  505.         if (tmp == (object *) NULL) {
  506.                 new_draw_info(NDI_UNIQUE, 0,op, "The Shop is currently empty.");
  507.             op->contr->state = ST_PLAYING;    /* reset to normal state */
  508.                 free_object(op->contr->menu);
  509.                 op->contr->menu = NULL;
  510.                 return;
  511.         }
  512.     /* If the person is using scroll, a blank line is probably better
  513.          * than clearing the window.  Clearing the window is better for
  514.          * people that do not use scroll.  Mark Wedel (master@rahul.net)
  515.          */
  516.  
  517.     if (op->contr->scroll)
  518.         new_draw_info(NDI_UNIQUE, 0,op, "");  /* add a blank line for readability */
  519.     else
  520.         clear_win_info(op); /* Seems more readable and faster to me.  -Frank */
  521.  
  522.     if (op->contr->state==ST_MENU_MORE)
  523.         new_draw_info(NDI_UNIQUE, 0,op, "The Shop contains (continued):");
  524.     else
  525.         new_draw_info(NDI_UNIQUE, 0,op, "The Shop contains:");
  526.     do {
  527.         /* mark object as being paid, so that '(unpaid)' isn't
  528.         added to the end -- By definition, an object being
  529.         viewed in the shop listing is unpaid.
  530.         */
  531.         CLEAR_FLAG(tmp, FLAG_UNPAID);
  532.         /* Give a little more detail on some items.
  533.          * After all, telling the person that there is 5
  534.          * rings in the shop isn't especially useful.
  535.          */
  536.         switch (tmp->type) {
  537.             case RING:
  538.             case AMULET:
  539.             case BRACERS:
  540.             case BOOTS:
  541.             case GLOVES:
  542.             case GIRDLE:
  543.             new_draw_info_format(NDI_UNIQUE, 0, op,
  544.             "%s %s",query_name(tmp),
  545.                 describe_item(tmp));
  546.             break;
  547.             default:
  548.             new_draw_info(NDI_UNIQUE, 0,op, query_name(tmp));
  549.             break;
  550.         }
  551.         old = tmp;
  552.         tmp = tmp->below;
  553.         remove_ob(old);
  554.         free_object(old);
  555.         /* If we have put so many lines of inventory on the
  556.          * screen AND there is more to print, ask for them
  557.          * to enter a key.
  558.          */
  559.         if (++lines>op->contr->infolines && tmp)  {
  560.             new_draw_info(NDI_UNIQUE, 0,op,"Press any key to continue list");
  561.             op->contr->state = ST_MENU_MORE;
  562.             if (op->contr->eric_server>0)
  563.                 send_query(op->contr->eric_server,CS_QUERY_SINGLECHAR,"");
  564.             return;    /* let the routine in player.c handle the rest */
  565.         }
  566.  
  567.     } while (tmp);
  568.     free_object(op->contr->menu);
  569.     op->contr->menu = NULL;
  570.     op->contr->state = ST_PLAYING;    /* reset to normal state */
  571. }
  572.  
  573.  
  574. void shop_listing(object *op)
  575. {
  576.     int i,j;
  577.     char *map_mark = (char *) malloc(op->map->mapx * op->map->mapy);
  578.     object    *tmp,*stack;
  579.  
  580.     memset(map_mark, 0, op->map->mapx * op->map->mapy);
  581.     magic_mapping_mark(op, map_mark, 3);
  582.  
  583.     if (op->contr->menu!=NULL) {
  584.         LOG(llevError,"Shop listing being called with non null menu point in player\n");
  585.         return;
  586.     }
  587.     op->contr->menu = get_object();
  588.     for (i=0; i<op->map->mapx; i++)
  589.         for (j=0; j<op->map->mapy; j++) {
  590.         if (map_mark[i + op->map->mapx * j]) {
  591.             stack  =get_map_ob(op->map,i,j);
  592.             while (stack) {
  593.             if (QUERY_FLAG(stack, FLAG_UNPAID)) {
  594.                 tmp = get_object();
  595.                 copy_object(stack, tmp);
  596.                 (void) insert_ob_in_ob(tmp, op->contr->menu);
  597.             }
  598.             stack = stack->above;
  599.             }
  600.         }
  601.         }
  602.     free(map_mark);
  603.     shop_listing_more(op);
  604. }
  605.  
  606.